/* 房间函数原型扩展 */
import {LeastHit,filter_structure, zipPosition, isInArray, removeArray} from '@/utils'
import structure from '../structure'

export default class RoomFunctionExtension extends Room {
    /* 获取指定类型的type的建筑列表 */
    public getStructure(sc:StructureConstant):Structure[]
    {
        return this.find(FIND_STRUCTURES,{filter:{structureType:sc}})
    }

    public getTypeStructure(sr:StructureConstant[]):Structure[]
    {
        var resultstructure = this.find(FIND_STRUCTURES,{filter:(structure)=>{
            return filter_structure(structure,sr)
        }})
        return resultstructure
    }

    /* 获取指定类型type中,hit最小的建筑(是比值) */
    public getHitsleast(sc:StructureConstant,mode?:number):Structure | undefined
    {
        if (!mode) mode = 2
        /* 3 */
        if (mode == 3) mode = 0
        let s_l = this.find(FIND_STRUCTURES,{filter:(structure)=>{
            return structure.structureType == sc && structure.hits < structure.hitsMax
        }})
        let least_ = LeastHit(s_l,mode,)
        return least_
    }

    /* 获取指定列表中类型的type的建筑列表 */
    public getListStructure(sc:StructureConstant[]):Structure[]
    {
        return this.find(FIND_STRUCTURES,{filter:(structure)=>{
            return filter_structure(structure,sc)
        }})
    }

    /* 获取指定列表中类型的hit最小的建筑 (比值) 返回值： Structure | undefined */
    public getListHitsleast(sc:StructureConstant[],mode?:number):Structure | undefined
    {
        if (!mode) mode = 2
        /* 3 */
        if (mode == 3) mode = 0
        let s_l = this.find(FIND_STRUCTURES,{filter:(structure)=>{
            return filter_structure(structure,sc) && structure.hits < structure.hitsMax
        }})
        let least_ = LeastHit(s_l,mode,)
        return least_
    }

    /* 通过id获取该房间内想要的任何对象 */
    public ID(id:string):Structure | Creep | ConstructionSite | Flag | Source |Mineral{
        var sample = Game.getObjectById(id) as Structure | Creep | ConstructionSite | Flag | Source |Mineral
        if (sample && sample.room == this)
        {
            return sample
        }
        else
        {
            console.log("找不到对象，sample为:"+sample)
            return undefined
        }
    }

    /* 获取房间内所有 standed为true的爬虫的位置集合 */
    public getStandedPos():RoomPosition[]
    {
        var standedCreep = this.find(FIND_MY_CREEPS,{filter:(creep)=>{
            return creep.memory.standed == true
        }})
        if (standedCreep.length > 0)
        {
            var posList = []
            for (var i of standedCreep)
            {
                posList.push(i.pos)
            }
            // console.log(posList)
            return posList
        }
        return []
    }

    /* 获取房间内所有不是自己的爬虫的位置 */
    public getEnemyPos():RoomPosition[]{
        var hostile_creep = this.find(FIND_HOSTILE_CREEPS)
        if (hostile_creep.length > 0)
        {
            var result:RoomPosition[] = []
            for (var i of hostile_creep) result.push(i.pos)
            return result
        }
        return []
    }

    // 将pos对象序列化 例： 43\12\W1N1
    public serializePos(position : RoomPosition):string{
        var x_ = position.x
        var y_ = position.y
        var room_name = position.roomName
        return `${x_}/${y_}/${room_name}`
    }

    // 解压房间内字符串获取pos对象
    public unzip(str:string):RoomPosition | undefined{
        var info = str.split('/')
        return info.length == 2? new RoomPosition(Number(info[0]),Number(info[1]),this.name):undefined
    }

    /* 寻找房间内远离controller的资源点 */
    public findFarSource():Source | undefined
    {
        var sources = this.find(FIND_SOURCES)
        if (sources.length <= 0) return undefined
        if (sources.length == 1) return sources[0]
        if (sources.length >= 2){
            var closest_source = this.controller.pos.findClosestByRange(FIND_SOURCES)
            for (var index of sources)
            {
                if (index != closest_source)
                return index
            }
        }
    }

    /* 寻找房间中心点range_格以内的指定建筑列表内的建筑，mode=0不指定。mode=1受损的列表，mode=2hit最小的建筑 */
    // 尚未测试，可靠性未知
    public findNearStructure(range_:number,conList:StructureConstant[],mode:number):Structure[] | Structure | undefined {
        // 如果有中心点就选择中心点，没有中心点就选择storage作为中心点，否则选择25，25为中心点
        var x:number; var y:number
        if (this.memory.center_x && this.memory.center_y){x = this.memory.center_x ; y = this.memory.center_y}
        else if (this.getStructure(STRUCTURE_STORAGE).length == 1){
            var storage_ = this.getStructure(STRUCTURE_STORAGE)[0]
            x = storage_.pos.x
            y = storage_.pos.y
        }
        else {x = 25; y = 25}
        var position_ = new RoomPosition(x,y,this.name)
        var conList:StructureConstant[]
        return position_.getRangedStructure(conList,range_,mode)
    }


    /* 获取tower伤害地形数据 */
    public TowerRangeMap():void{
        if (!global.towerRangeData) global.towerRangeData = {}
        /* 创建临时数据 */
        var terrianData = this.getTerrain()
        let tempData:TowerRangeMapData = {}
        // 获取该房间内所有的塔
        var Towers = this.getStructure('tower') as StructureTower[]
        for (var i=0;i<50;i++)
        LoopTerrian:
        for (var j=0;j<50;j++)
        {
            var thisPos = new RoomPosition(i,j,this.name)
            // 0 平原 1 墙壁 2 沼泽
            if (terrianData.get(i,j) == 1)
                continue LoopTerrian
            let tempNum:ARH = {attack:0,heal:0,repair:0}
            for (var t of Towers)
            {
                // 伤害计算叠加
                thisPos.AddTowerRangeData(t,tempNum)
            }
            tempData[`${thisPos.x}/${thisPos.y}`] = tempNum
        }
        global.towerRangeData[this.name] = tempData
    }

    /* lab绑定函数添加 初次添加可以删除 lab的ID 最大同时占有数量  */
    public BindLab(ID:string,MissonID:string,rType:ResourceConstant):boolean{
        if (!this.memory.TaskData.OccupiedLab[ID]) return false
        var thisList = this.memory.TaskData.OccupiedLab[ID].relate as string[]
        if (!isInArray(thisList,MissonID) && !this.FullBindLab(ID) && this.TypeBindLab(ID,rType))
        {
            thisList.push(MissonID)
            this.memory.TaskData.OccupiedLab[ID].rType = rType
            return true
        }
        console.log(`实验室绑定出现未知错误!`)
        return false
    }
    /* lab解绑函数 */
    public UnBindLab(ID:string,MissionID:string):boolean{
        if (!this.memory.TaskData.OccupiedLab[ID]) return false
        var relateList = this.memory.TaskData.OccupiedLab[ID].relate as string[]
        if (isInArray(relateList,MissionID))
        {
            if (relateList.length <= 1)
            {
                delete this.memory.TaskData.OccupiedLab[ID]
            }
            else
                removeArray(relateList,MissionID)
            return true
        }
        return false
    }
    /* lab查询绑定函数 */
    public CheckBindLab(ID:string,MissionID):boolean{
        if (!this.memory.TaskData.OccupiedLab[ID]) return false
        var relateList = this.memory.TaskData.OccupiedLab[ID].relate as string[]
        if (isInArray(relateList,MissionID)) return true
        return false

    }
    /* lab查询绑定是否已经满溢  ture 表示已经满溢，不能再绑定了*/
    public FullBindLab(ID:string):boolean{
        /* 不存在说明可以绑定，所以判定为false */
        if (!this.memory.TaskData.OccupiedLab[ID]) return false
        var relateList = this.memory.TaskData.OccupiedLab[ID].relate as string[]
        var relateNum = this.memory.TaskData.OccupiedLab[ID].num as number
        if (relateList.length >= relateNum)
            return true
        return false

    }
    /* lab绑定初始化函数 */
    public InitBindLab(ID:string,num:number,rType:ResourceConstant):void{
        if (!this.memory.TaskData.OccupiedLab[ID] || this.memory.TaskData.OccupiedLab[ID].rType != rType)
        {
            this.memory.TaskData.OccupiedLab[ID] = {}
            this.memory.TaskData.OccupiedLab[ID].num = num
            this.memory.TaskData.OccupiedLab[ID].relate = [] // 任务ID
        }
    }
    /* lab绑定num修改函数 */
    public NumBindLab(ID:string,num:number):boolean{
        if (!this.memory.TaskData.OccupiedLab[ID]) return false
        if (this.memory.TaskData.OccupiedLab[ID].num != num)
            this.memory.TaskData.OccupiedLab[ID].num = num
        return true
    }

    /* lab绑定资源对型判断函数 */
    public TypeBindLab(ID:string,rType:ResourceConstant):boolean{
        if (!this.memory.TaskData.OccupiedLab[ID]) return true
        if (!this.memory.TaskData.OccupiedLab[ID].rType) return true
        if (this.memory.TaskData.OccupiedLab[ID].rType != rType)
            return false
        return true
    }

}
